import { sameOffsetNode } from '../element/sameOffsetNode';
import {
  domTree,
  endsTimeAnimation,
  ObjectOnlyPushSet,
  removeClass,
  settimeNth,
  toStringTypeCheck,
} from '../global';
import { evalString } from '../evalString/evalString';
import { SetStaticCssTxtFunc } from '../globalStyleFunc/setStaticCssTxtFunc';
import {
  getElementOffsetPosi,
  getElementViewOffsetPosi,
} from '../element/getElementViewOffsetPosi';

let prefix_fta = 'FTA';

let unitArr = { data: [] };

let splitStr = '_';

// 申请 全局 staticCss 工厂 调用 "fromtoAnimaF" 空间
let styleFunc = SetStaticCssTxtFunc('fromtoAnimaF');

let regClassName = /\.(?<className>.*?)\{/;

let FromToAnimastyle_S = splitStr + 'fromToAnima';

let virtualDomData = {
  queue: ['a'],
  a: {
    tag: 'div',
    attribute: ['value'],
    props: ['classList', 'id'],

    classList: ['VirtualDom', 'posiAb', 'VirDomStyle'],
    id: '',
    value: '',
  },
};
let unitS = 0;

/**
 * 创建 可移动 元素 工厂
 * @param {Element} virtualDom 给定 dom 元素 或者 （给定 domTree ||默认生成 元素） 到body
 * 
 * 返回元素
 * {
 * useDom,
    currentStyleDom,
    fromElto,
    getTransformEl,
    KeyframeModel,
    useStyleModelAndFunc,
    addBeforeAnimaFuncS,
    addAfterAnimaFuncS,
}
 */
function fromtoAnimaF(virtualDom) {
  let that = this;

  //当前 virtualDom 索引位置
  let currentVirDomIndex;

  //当前 选中 Dom 元素
  let currentDom;

  // 当前 所 使用的 组件 元素
  let currentStyleDom;

  /**
   * 起始元素
   */
  let fromEl;

  /**
   * 目标元素
   */
  let toEl;

  //元素 全局记载
  let Wuid = window.Wuid;

  // 所使用的 keyframe  Model
  let KeyframeModel = undefined;

  /**
   * 所使用的 keyframe 的 函数字典
   *
   * 绑定的 fromEl(poa) toEl(pob) call.this= {poa,pob}
   */
  let keyframeModelFunc;

  let keyframeModelClass;

  // 用户 是否 自定义了 animation 组件
  let userKeyframe = false;

  // 是否 在 同一 上一级位置影响元素
  let isSameOffsetNode = false;

  //添加动画前 运行的 函数 组
  let beforeArrFun = { data: [] };

  //添加动画后 运行的 函数 组
  let afterArrFun = { data: [] };

  //创建 uid 承载体
  if (Wuid == undefined) {
    window.Wuid = { data: [] };
    Wuid = window.Wuid;
    currentVirDomIndex = 0;
  } else {
    currentVirDomIndex = Wuid['data'].length;
  }

  //装配 节点
  initVirtualDom();

  //   //装配 节点 Style 样式
  //   initStyleFunc();

  //装配 信息 到 window.Wuid
  loadWuid();

  /**
   * 根据不同 需求 装配 节点 尽量使用 同级 变换
   */
  function initVirtualDom() {
    //采用 body _div#VirtualDom#posiAb#VirDomStyle.WinUid
    if (virtualDom == undefined) {
      rebuildVDomData();
      //获取 到 新创建 的 节点
      currentDom = domTree(undefined, virtualDomData);

      //   添加 新创建节点 到 body 元素
      document.body.appendChild(currentDom);
    } else if (virtualDom.nodeType == 1) {
      useDom(virtualDom);
    } else if (
      virtualDom['queue'] != undefined &&
      virtualDom['queue'].length == 1
    ) {
      //获取 用户 自定义 DomTree 元素 的 节点
      currentDom = domTree(undefined, virtualDom);

      //   添加 新创建节点 到 body 元素
      document.body.appendChild(currentDom);
    }
  }

  /**
   * 装配 style 信息 --staticCss [currentVirId]
   * @param {String} styleCode  style Code
   */
  function initStyleFunc(styleCode) {
    styleFunc(
      Wuid[Wuid['data'][currentVirDomIndex]]['currentDom'].id +
        FromToAnimastyle_S,
      styleCode
    );
  }

  /**
   * 替换 currentDom
   * @param {Element} el 使用 用户指定 element
   */
  function useDom(el) {
    if (el.nodeType != 1) {
      console.log('useDom need a Document.element');
      return;
    }

    //跟进 节点
    currentDom = el;

    //删除 element占位
    delete window.Wuid[window.Wuid['data'][currentVirDomIndex]];

    //重新 装载 当前 节点
    loadWuid(window.Wuid['data'][currentVirDomIndex]);
  }

  //创建唯一 Uid
  function createWinUid() {
    return currentDom.id + splitStr + currentVirDomIndex;
  }

  /**
   * 装配 信息 到 window.Wuid
   */
  function loadWuid(c) {
    if (c == undefined) {
      c = createWinUid();
      if (Wuid['data'].indexOf(c) > -1) {
        console.log('hh 小概率 事件 wiud 新生成的 Uid 碰到 一起了');
        loadWuid();
        return;
      }
      Wuid['data'].push(c);

      currentVirDomIndex = Wuid['data'].length - 1;
    }
    Wuid[c] = {
      data: ['currentDom', 'fromElement', 'toElment', 'KeyframeModel'],
      currentDom,
    };
  }

  /**
   * 重新装载 VirtualDomData
   * 实时更改 id 和 value 默认为 virtDom_index
   */
  function rebuildVDomData() {
    let fillV = 'virtDom' + splitStr + currentVirDomIndex;
    virtualDomData[virtualDomData['queue'][0]]['id'] = fillV;
    virtualDomData[virtualDomData['queue'][0]]['value'] = fillV;
  }

  /**
   * 元素单项移动帧 从一个元素位置 移动到 另一个元素位置 <位置 和 宽高>
   * @param {Element} fromElement 元素 起始位置
   * @param {Element} toElement 元素 结束位置
   */
  function fromElto(fromElement, toElement) {
    // console.dir(fromEl);
    // console.dir(toEl);
    fromEl = fromElement;
    toEl = toElement;
    isSameOffsetNode = sameOffsetNode(fromEl, toEl).isSameOffsetNode;

    // 在不同 位置级 元素下 重新复制一个框架元素
    if (!isSameOffsetNode) {
      let cloneEl = currentDom.cloneNode(false);
      cloneEl.style = 'background-color: blueviolet;';
      document.body.appendChild(cloneEl);
      useDom(cloneEl);
    }

    let fromElPosi = getElementPosi(fromEl);
    let toElPosi = getElementPosi(toEl);

    KeyframeSettle(fromElPosi, toElPosi);

    beforeAniam(beforeArrFun);

    let delayTime = endsTimeAnimation(
      Wuid[Wuid['data'][currentVirDomIndex]]['currentDom'],
      keyframeModelClass,
      undefined,
      false
    );
    settimeNth([0, delayTime], () => {
      console.log(Wuid, currentVirDomIndex);
      afterAniam(afterArrFun);
    });
  }

  function getElementPosi(el) {
    // console.dir(el);
    if (isSameOffsetNode) {
      return getElementOffsetPosi(el);
    } else {
      return getElementViewOffsetPosi(el);
    }
  }

  /**
   * 组装 keyframe
   * @param {Object} poa
   * @param {Object} pob
   */
  function KeyframeSettle(poa, pob) {
    if (userKeyframe) {
      let userKeyframeA = userKeyframeSettle(poa, pob);
      initStyleFunc(userKeyframeA);
    } else {
      initStyleFunc(defaultKeyframe(poa, pob));
    }
  }

  function userKeyframeSettle(poa, pob) {
    return evalString(KeyframeModel, keyframeModelFunc.call({ poa, pob }));
  }

  /**
   * 应用用户自定义 的模板函数
   * @param {String} str
   * @param {Function} fun
   */
  function useStyleModelAndFunc(str, fun) {
    userKeyframe = true;
    KeyframeModel = str;
    keyframeModelFunc = fun;
    keyframeModelClass = regClassName.exec(str).groups['className'].trim();
  }

  function defaultKeyframe(poa, pob) {
    let domId = Wuid[Wuid['data'][currentVirDomIndex]]['currentDom'].id;
    let defaultKeyframeModel = `.default_FromToAnima_${domId} {
        position: absolute;
        animation-name: default_FTA_${domId};
        animation-duration: 10s;
        animation-timing-function: ease-in-out;
        animation-fill-mode: forwards;
      }
      
      @keyframes default_FTA_${domId} {
        from {
          Top: &{poa.offsetTop}&px;
          Left: &{poa.offsetLeft}&px;
      
          Width: &{poa.width}&px;
          Height: &{poa.height}&px;
        }
        to {
          Top: &{pob.offsetTop}&px;
          Left: &{pob.offsetLeft}&px;
      
          Width: &{pob.width}&px;
          Height: &{pob.height}&px;
        }
      }`;
    keyframeModelClass = regClassName
      .exec(defaultKeyframeModel)
      .groups['className'].trim();

    return evalString(defaultKeyframeModel, { poa, pob });
  }

  /**
   * 在 运行动画 前 暴露 一些信息 可供 用户自定义函数进行操作
   * 暴露 currentDom 节点
   *
   * @param {Object} arrFun 函数 数组 {data:[fun1],fun1:function}
   */
  function beforeAniam(arrFun) {
    if (
      arrFun != undefined &&
      toStringTypeCheck(arrFun['data'], 'array') &&
      arrFun['data'].length > 0
    ) {
      let expProp = ExposeProperty();
      console.log(expProp);
      for (let i = 0; i < arrFun['data'].length; i++) {
        if (toStringTypeCheck(arrFun[arrFun['data'][i]], 'function')) {
          arrFun[arrFun['data'][i]].call(expProp);
        }
      }
    }
  }

  /**
   * 在 运行动画 后 暴露 一些信息 可供 用户自定义函数进行操作
   * 暴露 currentDom 节点
   *
   * @param {Array} arrFun 函数数组
   */
  function afterAniam(arrFun) {
    beforeAniam(arrFun);
  }

  /**
   * 切片 节点
   * @returns
   */
  function ExposeProperty() {
    console.log(
      currentVirDomIndex,
      Wuid[Wuid['data'][currentVirDomIndex]]['currentDom']
    );
    return {
      currentDom:
        Wuid[Wuid['data'][currentVirDomIndex]]['currentDom'] || that.currentDom,
    };
  }

  /**
   * 添加 动画运行 前 的 函数
   * @param {String} title 函数 表述符
   * @param {Function} func 待启用函数
   * @returns boolean
   */
  function addBeforeAnimaFuncS(title, func) {
    let pushB = ObjectOnlyPushSet(beforeArrFun, title, func);
    if (!pushB) {
      console.log(
        "you already settle the same title in BeforeArrfun title is: '" +
          title +
          "'\n func:" +
          func
      );
      return false;
    }
    return true;
  }

  /**
   * 添加 动画运行 后 的 函数
   * @param {String} title 函数 表述符
   * @param {Function} func 待启用函数
   * @returns boolean
   */
  function addAfterAnimaFuncS(title, func) {
    let pushA = ObjectOnlyPushSet(afterArrFun, title, func);
    if (!pushA) {
      console.log(
        "you already settle the same title in afterArrFun title is: '" +
          title +
          "'\n func:" +
          func
      );
      return false;
    }
    return true;
  }

  /**
   * 辅助填充
   * -
   * 在 同源 元素下  由于 改变 fromEl 会有元素跳动
   *
   * 因此 设置 元素的 填充确保 元素 在 position:absolute 时 不会跳动
   *
   * 在 动画完成后 再进行删除元素
   */
  function AuxiliaryFill() {
    let disappearClass = prefix_fta + splitStr + 'disappear';

    let AppearClass = prefix_fta + splitStr + 'appear';
    // console.log(currentDom);
    // 克隆一个复制体 元素
    let cloneNode = currentDom.cloneNode(false);

    let posi = getElementOffsetPosi(currentDom);
    console.log(posi);
    // 单元组件大小class
    let unitSizeClass = getunitClass(posi);

    //添加 组件大小
    removeClass(cloneNode, unitSizeClass, true);

    // 高度逐渐变小 在一定时间后 删除该元素
    // removeClass(cloneNode, disappearClass, true);

    //1.0 残留影子 放置在 起始元素的位置 起始元素 被设置为 position:absolute; 时
    fromEl.parentNode.insertBefore(cloneNode, fromEl);
    //2.1 添加 目标元素 的 扩充class
    removeClass(toEl, AppearClass, true);

    // 高度逐渐变小 在一定时间后 删除该元素
    let disappearTime = endsTimeAnimation(cloneNode, disappearClass);

    settimeNth([0, disappearTime], () => {
      //2.0 动画事件后 删除 残留影子
      cloneNode.remove();
      //2.1 移除 目标元素 的 扩充class
      removeClass(toEl, AppearClass);
    });
  }

  /**
   * 补充函数 --补丁
   */
  function reviserFun() {
    addBeforeAnimaFuncS('filluseNode', AuxiliaryFill);
  }
  reviserFun();

  return {
    useDom,
    currentStyleDom,
    fromElto,
    get getTransformEl() {
      return Wuid[Wuid['data'][currentVirDomIndex]]['currentDom'];
    },
    KeyframeModel,
    useStyleModelAndFunc,
    addBeforeAnimaFuncS,
    addAfterAnimaFuncS,
  };
  //   return returninfo;
}

/**
 * 获取
 * @param {String} unitSize -- 目标元素的 单元大小 size class String (完整style)
 * @returns
 */
function getunitClass(posi) {
  let unitSizeClass = `${prefix_fta}${splitStr}unit${splitStr}${unitS}`;

  let unitSize = `.${unitSizeClass} {
        width: ${posi.width}px;
        height: ${posi.height}px;
       }`;
  if (unitSize != unitArr[unitSizeClass]) {
    let i = 0;
    for (; i < unitArr['data'].length; i++) {
      if (unitSize == unitArr[unitArr['data'][i]]) {
        unitSizeClass = unitArr['data'][i];
        return unitSizeClass;
      }
    }
    unitS = i + 1;
    unitSizeClass = `${prefix_fta}${splitStr}unit${splitStr}${unitS}`;
    unitSize = `.${unitSizeClass} {
        width: ${posi.width}px;
        height: ${posi.height}px;
       }`;
    unitArr['data'].push(unitSizeClass);
    unitArr[unitSizeClass] = unitSize;
    styleFunc(unitSizeClass, unitSize);
  }
  return unitSizeClass;
}

export { fromtoAnimaF };
//done 2023.10.24 17:35 晴 星期二 好像写完了
//modify 2024.03.24 23:42 雨 星期日 这几天 修改了一下 这个 fromToEl 功能 想吃 吕游 的 18cm 大鸡巴
//2024.03.25 23:24 阴 星期日 commit -m "这次上传 不知道写什么了 昨天 想到了 一个关于 未来 自动运行的代码结构 根据 计时器-运行代码 就是在: 时间运行后 添加时间计数器 运行下一次代码 这个时间 间隔 是 确定的 固定刷新 也可以 定制时间 运行 &{想吃 吕游 大鸡巴 想被操 想被照顾 喜欢男人 喜欢大的 喜欢有趣的}&"
